float4x4 World;
float4x4 View;
float4x4 Projection;
float4 ColorLight = float4(1, 1, 1, 1);
float4 AmbientLightColor = float4(1, 1, 1, 1);
float LightIntensity = 0.5;
float3 LightDirection;
float SpecularPower;
float4 EmissiveColor;
float3 Ka, Kd, Ks;
float3 CameraPos;
float3 ViewVector;
float FogStart;
float FogEnd;
float3 FogColor;

Texture WorldTexture;
samplerCUBE WorldSampler = sampler_state
{
	Texture = <WorldTexture>;
	MagFilter = Linear; 
    MinFilter = Linear; 
    MipFilter = Linear; 
    AddressU = Mirror; 
    AddressV = Mirror; 
};

Texture BumpMap;
sampler2D bumpSampler = sampler_state
{
	Texture = <BumpMap>;
	MinFilter = Linear;
	MagFilter = Linear;
	AddressU = Wrap;
	AddressV = Wrap;
};

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float3 Normal : NORMAL0;
	float3 Tangent : TANGENT0;
	float2 Texture : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
	float3 Normal : TEXCOORD0;
	float3 H : TEXCOORD1;
	float2 Texture : TEXCOORD2;
	float Depth : TEXCOORD3;
	float3 Tangent : TEXCOORD4;
	float3 ViewDirection : TEXCOORD5;
};

float3 GetBmpNormal(float3 Normal, float3 Tangent, float2 TexCoord)
{
	float3 tangentN = 2.0 * tex2D(bumpSampler, TexCoord) - 1.0;

	float3 worldT = normalize(Tangent);
	float3 worldN = normalize(Normal);
	float3 worldB = cross(worldN, worldT);

	return normalize(tangentN.x * worldT + tangentN.y * worldB + tangentN.z * worldN);
}

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;
 
    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);
	output.ViewDirection = CameraPos - worldPosition;

	float3 H = normalize( -LightDirection + ViewVector);
	float3 Normal = normalize( mul( input.Normal, World) );
	
	output.Normal = Normal;
	output.H = H;
	output.Texture = input.Texture;
	output.Depth = output.Position.z;
	output.Tangent = normalize( mul(input.Tangent, World));

    return output;
}


float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	input.Normal = normalize(input.Normal);
	input.H = normalize(input.H);
	
	float3 bump = GetBmpNormal(input.Normal, input.Tangent, input.Texture);
	float3 reflection = reflect(-normalize(input.ViewDirection), bump);
	float4 enviornmentColor = float4(texCUBE(WorldSampler, normalize(reflection)).xyz,0);

	// Ambient intensity
    float Ia = AmbientLightColor * Ka + 0.1; // Add a little more brightness to the ambient light (+ 0.1)

	// Diffuse intensity
	float Id = saturate(dot(input.Normal, -LightDirection)) * Kd * 0.4;

	// Specular intensity
	float Is = pow(saturate(dot(input.Normal, input.H)), SpecularPower) * 0.5;

	// Fog
	float l = saturate((input.Depth - FogStart) / (FogEnd - FogStart));

	return float4(lerp(enviornmentColor,FogColor,l),1);
}

technique Technique1
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
